"use client"; import AutoEssayTitleView from "@/app/[language]/forum/components/AutoEssayTitleView"; import TextView from "@/app/[language]/forum/components/TextView"; import useGetAutoEssay from "@/app/[language]/forum/query/useGetAutoEssay"; import useGetEssay from "@/app/[language]/forum/query/useGetEssay"; import usePostAutoEssay from "@/app/[language]/forum/query/usePostAutoEssay"; import usePostEssay from "@/app/[language]/forum/query/usePostEssay"; import usePostFile from "@/app/[language]/forum/query/usePostFile"; import usePutAutoEssay from "@/app/[language]/forum/query/usePutAutoEssay"; import usePutEssay from "@/app/[language]/forum/query/usePutEssay"; import { useForumStore, useTaehuiStore } from "@/state/Stores"; import { observer } from "mobx-react-lite"; import { useTranslations } from "next-intl"; import { useParams } from "next/navigation"; import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { toast } from "react-toastify"; import { Button, Col, Collapse, Input, ListGroup, Modal, ModalBody, Row, TabContent, TabPane, } from "reactstrap"; import { useTo, useWindowArea } from "taehui-ts/fe-utilities"; export default observer(() => { const { isTitleTextFilled, title, text, setTitle, setText, autoEssayID, setAutoEssayID, } = useForumStore(); const { titleViewHeight, avatarViewHeight } = useTaehuiStore(); const { taehuiAvatarID, taehuiAvatarName } = useTaehuiStore(); const t = useTranslations(); const [isTestMode, setTestMode] = useState(false); const [testText, setTestText] = useState(""); const [textViewHeight, setTextViewHeight] = useState(100); const [isAutoEssayOpened, setAutoEssayOpened] = useState(false); const { forumID, essayID } = useParams<{ forumID: string; essayID?: string; }>(); const { isFetched: isAutoEssayLoaded, data: autoEssay } = useGetAutoEssay( forumID, isAutoEssayOpened, ); const editView = useRef<HTMLDivElement>(null); const textView = useRef<HTMLTextAreaElement>(null); const inputView = useRef<HTMLDivElement>(null); const { mutateAsync: postAutoEssay } = usePostAutoEssay(); const { mutateAsync: putAutoEssay } = usePutAutoEssay(); const { mutateAsync: putEssay } = usePutEssay(); const { isPending, mutateAsync: postFile } = usePostFile(); const { mutateAsync: postEssay } = usePostEssay(); const { data: essay, data: { forumTitle }, isFetched: isEssayLoaded, } = useGetEssay(essayID); useEffect(() => { if (isEssayLoaded) { setTitle(essay.title); setText(essay.text); } }, [essay, isEssayLoaded, setText, setTitle]); const { windowHeight } = useWindowArea(); const to = useTo(); const setTag = (tag: string) => { const { current } = textView; if (current) { const { selectionStart, selectionEnd } = current; const t = text.substring(selectionStart, selectionEnd); const tag0 = "<" + tag + ">"; const tag1 = "</" + tag + ">"; if (t.startsWith(tag0) || t.endsWith(tag1)) { setText( text.substring(0, selectionStart) + text.substring( selectionStart + tag0.length, selectionStart + t.length - tag1.length, ) + text.substring(selectionEnd), ); setTimeout(() => { current.selectionStart = selectionStart; current.selectionEnd = selectionEnd - tag0.length - tag1.length; current.focus(); }, 0); } else { setText( text.substring(0, selectionStart) + tag0 + text.substring(selectionStart, selectionEnd) + tag1 + text.substring(selectionEnd), ); setTimeout(() => { current.selectionStart = selectionStart; current.selectionEnd = selectionEnd + tag0.length + tag1.length; current.focus(); }, 0); } } }; useEffect(() => { setTextViewHeight( windowHeight - titleViewHeight - avatarViewHeight - (editView.current?.clientHeight ?? 0) - (inputView.current?.clientHeight ?? 0), ); }, [avatarViewHeight, titleViewHeight, windowHeight]); useEffect(() => { if (!essayID) { setTitle(""); setText(""); } }, [essayID, setText, setTitle]); useEffect(() => { const postAutoEssaysID = setInterval(async () => { if (isTitleTextFilled) { if (typeof autoEssayID === "number") { await putAutoEssay({ autoEssayID, title, text }); } else { const { autoEssayID } = await postAutoEssay({ forumID, title, text, }); setAutoEssayID(autoEssayID); } } }, 60000); return () => { clearInterval(postAutoEssaysID); }; }, [ autoEssayID, forumID, isTitleTextFilled, postAutoEssay, putAutoEssay, setAutoEssayID, t, text, title, ]); useLayoutEffect(() => { if (isTestMode) { setTestText(text); } }, [isTestMode, text]); return ( <> {!isTestMode && ( <div ref={editView}> <Row className="g-0"> <Col className="m-1"> <Input invalid={!title} valid={!!title} placeholder={t("title")} value={title} onChange={({ target: { value } }) => { setTitle(value); }} /> </Col> </Row> <Row className="g-0"> <Col className="m-1" xs="auto"> <Button onClick={() => { const inputElement = document.createElement("input"); inputElement.type = "file"; inputElement.accept = "audio/*,image/*,video/*"; inputElement.addEventListener( "change", async ({ target }) => { const file = (target as HTMLInputElement).files?.[0]; const { current } = textView; if (file && current) { const text = await postFile({ file, textView: current, }); if (text) { setText(text); } } }, ); inputElement.click(); }} color="info" > {t("fileUpload")} </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setAutoEssayOpened((prevState) => !prevState); }} color={isAutoEssayOpened ? "secondary" : "primary"} > {t("autoEssays")} </Button> </Col> </Row> <Row className="g-0"> <Col className="m-1"> <Collapse isOpen={isAutoEssayOpened}> <ListGroup> {isAutoEssayLoaded ? ( autoEssay.map((autoEssay) => ( <AutoEssayTitleView key={autoEssay.autoEssayID} autoEssay={autoEssay} /> )) ) : ( <AutoEssayTitleView autoEssay={{ autoEssayID: 0, title: "Loading...", text: "", date: "", }} /> )} </ListGroup> </Collapse> </Col> </Row> </div> )} <Row className="g-0"> <Col className="m-1"> <TabContent activeTab={isTestMode ? 2 : 1}> <TabPane tabId={1}> <Input type="textarea" className="form-control" placeholder={t("text")} value={text} onChange={({ target: { value } }) => { setText(value); }} innerRef={textView} style={{ height: textViewHeight }} /> </TabPane> <TabPane tabId={2}> <TextView forumTitle={forumTitle} title={title} text={testText} avatarID={taehuiAvatarID} avatarName={taehuiAvatarName} /> </TabPane> </TabContent> </Col> </Row> <div ref={inputView}> <Row className="g-0"> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("strong"); }} color="info" > <strong>{t("textTag")}</strong> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("i"); }} color="info" > <i>{t("textTag")}</i> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("u"); }} color="info" > <u>{t("textTag")}</u> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("s"); }} color="info" > <s>{t("textTag")}</s> </Button> </Col> </Row> <Row className="g-0"> <Col className="m-1"> <Button color={isTestMode ? "primary" : "secondary"} onClick={() => { setTestMode((prevState) => !prevState); }} > {t("viewEditedEssay")} </Button> </Col> {essayID ? ( <Col className="m-1" xs="auto"> <Button color="warning" onClick={async () => { if (title && text) { await putEssay({ essayID, title, text }); to(`/forum/${forumID}/${essayID}`); } else { toast.error(t("failedValidation")); } }} > {t("doModifyEssay")} </Button> </Col> ) : ( <Col className="m-1" xs="auto"> <Button color="success" onClick={async () => { if (title && text) { const { essayID } = await postEssay({ forumID, title, text, }); to(`/forum/${forumID}/${essayID}`); } else { toast.error(t("failedValidation")); } }} > {t("postEssay")} </Button> </Col> )} <Col className="m-1" xs="auto"> <Button color="danger" onClick={() => { to(`/forum/${forumID}`); }} > {t("quit")} </Button> </Col> </Row> </div> <Modal isOpen={isPending}> <ModalBody> <span>{t("fileUploading")}</span> </ModalBody> </Modal> </> ); });